home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Online / NNTPd / server / spawn.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-12-09  |  7.8 KB  |  376 lines

  1. #ifndef lint
  2. static    char    sccsid[] = "@(#)$Id: spawn.c,v 1.32 1994/12/09 02:52:18 sob Exp sob $";
  3. #endif
  4.  
  5. #include "common.h"
  6.  
  7. #include <signal.h>
  8. #ifdef sparc
  9. #ifndef SVR4
  10. #include <vfork.h>
  11. #endif
  12. #endif
  13. #ifdef XFER_TIMEOUT
  14. static int    xfer_lines;
  15. static int    old_xfer_lines;
  16. #endif
  17.  
  18. static char    tempfile[256];
  19. #ifndef CNEWS
  20. static char    badfile[256];
  21. #endif
  22.  
  23. /*
  24.  * spawn -- create a child process with the input from the client
  25.  * as stdin.
  26.  *
  27.  *    Parameters:    "path" is the path of the program to invoke.
  28.  *            "name" is the name to call the program.
  29.  *            "flag" is a single flag to be passed to the program.
  30.  *            "cont_code" is the response code to transmit
  31.  *            on successful startup.
  32.  *            "err_code" is the response code to transmit when
  33.  *            something goes wrong.
  34.  *
  35.  *    Returns:    -1 on non-zero return from child,
  36.  *            0 on error before fork/exec,
  37.  *            1 otherwise.
  38.  *
  39.  *    Side effects:    Creates and removes temporary file;
  40.  *            accepts input from client; forks and execs.
  41.  *            Can time out if XFER_TIMEOUT is defined.
  42.  */
  43.  
  44. int
  45. spawn(path, name, flag, cont_code, err_code, errbuf, msg_id)
  46.     char        *path;
  47.     char        *name;
  48.     char        *flag;
  49.     int        cont_code;
  50.     int        err_code;
  51.     char        *errbuf;
  52.     char        *msg_id;
  53. {
  54.     char        line[NNTP_STRLEN]; /* XXX */
  55.     int        in_header;
  56.     register char    *cp;
  57.     int        i, fd;
  58.     int        fds[2];
  59.     int        pid, npid;
  60.     int        exit_status = 1;
  61. #ifdef POSTER
  62.     char *envp[4], user[sizeof(POSTER) + 5], logname[sizeof(POSTER) + 8];
  63.     char *home;
  64. #else
  65.     char *envp[1];
  66. #endif
  67. #ifdef XFER_TIMEOUT
  68.     SIGRET    xfer_timeout();
  69. #endif
  70. #if defined(USG) || defined(BSD_44)
  71.     int        status;
  72. #else
  73.     union wait    status;
  74. #endif
  75.     register FILE    *fp;
  76.  
  77. #ifdef GENAUTH
  78.     extern        char Host[], User[];
  79. #endif
  80.  
  81. #ifdef CNEWS
  82.     (void) strcpy(tempfile, "/tmp/rpostXXXXXX");
  83. #else
  84.     sprintf(tempfile, "%s/.tmp/rpostXXXXXX",SPOOLDIR);
  85. #endif
  86.     (void) mktemp(tempfile);
  87.  
  88.     fp = fopen(tempfile, "w");
  89.     if (fp == NULL) {
  90.         printf("%d Cannot create temporary file.\r\n", err_code);
  91.         (void) fflush(stdout);
  92.         return (0);
  93.     }
  94.  
  95.  
  96.     /*
  97.     * If this is a posting, rather than an XFER, leave a trail of
  98.     * breadcrumbs by stuffing where it came from into the header
  99.     */
  100.     if (cont_code == CONT_POST)
  101.         fprintf(fp, "X-Nntp-Posting-Host: %s\n", hostname);
  102. #ifdef AUTH
  103. #ifdef GENAUTH
  104.     if (cont_code == CONT_POST && Host[0] && User[0])
  105.         fprintf(fp, "Sender: %s@%s\n", User, Host);
  106. #endif
  107. #endif
  108.     in_header = 1;         /* in the header of the article */
  109.     printf("%d Ok\r\n", cont_code);
  110.     (void) fflush(stdout);
  111.  
  112. #ifdef XFER_TIMEOUT
  113.     xfer_lines = old_xfer_lines = 0;
  114.     signal(SIGALRM, xfer_timeout);
  115.     (void) alarm(XFER_TIMEOUT);
  116. #endif
  117.  
  118.     while (fgets(line, sizeof(line), stdin) != NULL) {
  119. #ifdef XFER_TIMEOUT
  120.         xfer_lines++;
  121. #endif
  122.         if ((cp = index(line, '\r')) != NULL)
  123.             *cp = '\0';
  124.         else if ((cp = index(line, '\n')) != NULL)
  125.             *cp = '\0';
  126.         if (line[0] == '.' && line[1] == '\0')
  127.             break;
  128.         if (strlen(line) == 0) 
  129.             in_header = 0;
  130.         if (in_header && 
  131.             (strncasecmp(line,"X-Nntp-Posting-Host:",20)==0)){
  132.                 line[0] = '\0';
  133.             continue;
  134.         }
  135.         if (in_header && 
  136.             (strncasecmp(line,"Nntp-Posting-Host:",18)==0)){
  137.                 line[0] = '\0';
  138.             continue;
  139.         }
  140. #ifdef AUTH
  141. #ifdef GENAUTH
  142.         if (in_header && (strncasecmp(line,"Sender:",7)==0)){
  143.                 line[0] = '\0';
  144.             continue;
  145.         }
  146. #endif
  147. #endif
  148.         if (line[0] == '.')
  149.             fputs(line+1, fp);
  150.         else
  151.             fputs(line, fp);
  152.         putc('\n', fp);
  153.     }
  154.     (void) fclose(fp);
  155.  
  156. #ifdef XFER_TIMEOUT
  157.     (void) alarm(0);
  158.     (void) signal(SIGALRM, SIG_DFL);
  159. #endif
  160.  
  161.     /* See if the connection got closed somehow... */
  162.  
  163.     if (line[0] != '.' && line[1] != '\0') {
  164.         (void) unlink(tempfile);
  165. #ifdef SYSLOG
  166. # ifdef LOG
  167.         syslog(LOG_ERR,
  168.             "%s spawn: EOF before period on line by itself %s",
  169.             hostname, msg_id);
  170. # else
  171.         syslog(LOG_ERR,
  172.             "spawn: EOF before period on line by itself %s", msg_id);
  173. # endif
  174. #endif
  175.         return (0);
  176.     }
  177.         
  178. #ifdef POSTER
  179.     if (tempfile[0])
  180.         (void) chown(tempfile, uid_poster, gid_poster);
  181. #endif
  182.  
  183.     /* Set up a pipe so we can see errors from rnews */
  184.  
  185.     if (pipe(fds) < 0) {
  186. #ifdef SYSLOG
  187.         syslog(LOG_ERR, "spawn: pipe: %m");
  188. #endif
  189.         (void) unlink(tempfile);
  190.         return (-1);
  191.     }
  192.  
  193.     /*
  194.      * Ok, now we have the article in "tempfile".  We
  195.      * should be able to fork off, close fd's 0 to 31 (or
  196.      * whatever), open "tempfile" for input, thus making
  197.      * it stdin, and then execle the inews.  We think.
  198.      */
  199. #ifdef SYSLOG
  200.     /*
  201.      * Close in such a way that syslog() will know to reopen.
  202.      * We must do this before the vfork() otherwise the parent
  203.      * will think the syslog fd is closed and open a new one,
  204.      * eventually using up all the available file descriptors.
  205.      */
  206.     closelog();
  207. #endif
  208.  
  209.     pid = vfork();
  210.     if (pid == 0) {        /* We're in child */
  211. #ifdef POSTER
  212. #ifndef USG
  213.         if (getuid() == 0) initgroups(POSTER,gid_poster);
  214. #endif
  215.         (void) setgid(gid_poster);
  216.         (void) setuid(uid_poster);
  217. #endif
  218.  
  219.         /* Set up stdout and stderr for child */
  220.  
  221.         if (fds[1] != 1) {
  222.             (void) dup2(fds[1], 1);
  223.             (void) close(fds[1]);
  224.         }
  225.         (void) dup2(1, 2);
  226.  
  227.         for (i = 3; i < 10; ++i) /* XXX but getdtablesize is too big */
  228.             (void) close(i);
  229.  
  230.         fd = open(tempfile, O_RDONLY);
  231.         if (fd != 0) {
  232.             (void) dup2(fd, 0);
  233.             (void) close(fd);
  234.         }
  235.  
  236.         /* Empty environment keeps cnews inews from telling lies */
  237. #ifdef POSTER
  238.         sprintf(user, "USER=%s", POSTER);
  239.         sprintf(logname, "LOGNAME=%s", POSTER);
  240.         if ((home = (char *)malloc(strlen(home_poster)+5+1)) != NULL)
  241.             sprintf(home, "HOME=%s", home_poster);
  242.         envp[0] = user;
  243.         envp[1] = logname;
  244.         envp[2] = home;
  245.         envp[3] = 0;
  246. #else
  247.         envp[0] = 0;
  248. #endif
  249.  
  250. #ifdef USG
  251.          /* execle() fails if name is a shell procedure */
  252.          execle("/bin/sh", "sh", path, flag, (char *)NULL, envp);
  253. #else
  254.         execle(path, name, flag, (char *) NULL, envp);
  255. #endif
  256.         fprintf(stderr, "spawn: execle(%s)", path);
  257.         perror(path);
  258. #ifdef SYSLOG
  259.         syslog(LOG_ERR, "spawn: execle(%s): %m", path);
  260. #endif
  261.         _exit(-1);    /* Error */
  262.         /*NOTREACHED*/
  263.     } else {    /* We're in parent. */
  264.         if (pid == -1) {
  265.             /* fork failed! */
  266.             printf("%d Cannot fork %s\r\n", err_code, path);
  267.             (void) fflush(stdout);
  268. #ifdef SYSLOG
  269.             syslog(LOG_ERR, "spawn: fork: %m");
  270. #endif
  271.             (void) unlink(tempfile);
  272.             return (0);
  273.         }
  274.         (void) close(fds[1]);
  275.         fp = fdopen(fds[0], "r");
  276.         if (fp == NULL) {
  277.             printf("%d Cannot fdopen %s pipe\r\n", err_code, path);
  278.             (void) fflush(stdout);
  279. #ifdef SYSLOG
  280.             syslog(LOG_ERR, "spawn: pipe: %m");
  281. #endif
  282.             (void) unlink(tempfile);
  283.             return (0);
  284.         }
  285.  
  286.         if (errbuf)
  287.             *errbuf = '\0';
  288.  
  289.         while (fgets(line, sizeof (line), fp) != NULL) {
  290.             if (line[0] != '\n') {
  291.                 if (errbuf) {
  292.                     if (cp = index(line, '\n'))
  293.                         *cp = '\0';
  294.                     (void) strcat(errbuf, line);
  295.                 }
  296. #ifdef SYSLOG
  297.                 syslog(LOG_INFO, "%s: %s", path, line);
  298. #endif
  299.             }
  300.         }
  301.  
  302.         while ((npid = wait(&status)) > 0)
  303.             if (npid == pid) {
  304. #if defined(USG) || defined(BSD_44)
  305.                 exit_status = (status >> 8) & 0xff;
  306. #else
  307.                 exit_status = status.w_T.w_Retcode;
  308. #endif
  309.                 break;
  310.             }
  311.  
  312.         (void) fclose(fp);
  313.         (void) fflush(stdout);
  314.         if (npid < 0) {
  315. #ifdef SYSLOG
  316.             syslog(LOG_ERR, "spawn: wait pid %d: %m", pid);
  317. #endif
  318.             return (-1);
  319.         }
  320.  
  321. #ifdef notdef
  322.         /* Make ctags happy */
  323.         {
  324. #endif
  325.         if (exit_status != 0) {
  326. #ifdef SYSLOG
  327.             syslog(LOG_ERR, "spawn: %s exit status %d",
  328.                 path, exit_status);
  329. #endif
  330.             /*
  331.              * Save the tempfile away in .bad.
  332.              */
  333. #ifdef CNEWS
  334.             }
  335.         (void) unlink(tempfile);
  336. #else
  337.             sprintf(badfile, "%s/.bad/nntpXXXXXX",SPOOLDIR);
  338.             (void) mktemp(badfile);
  339.             (void) rename(tempfile, badfile);
  340.         } else {
  341.             (void) unlink(tempfile);
  342.         }
  343. #endif            
  344.         return (exit_status ? -1 : 1);
  345.     }
  346. }
  347.  
  348. #ifdef XFER_TIMEOUT
  349. SIGRET
  350. xfer_timeout()
  351. {
  352.     if (old_xfer_lines < xfer_lines) {
  353.         old_xfer_lines = xfer_lines;
  354.         (void) signal(SIGALRM, xfer_timeout);
  355.         (void) alarm(XFER_TIMEOUT);
  356.         return;
  357.     }
  358.  
  359.     /* Timed out. */
  360.  
  361.     printf("%d timeout after %d seconds, closing connection.\r\n",
  362.         ERR_FAULT, XFER_TIMEOUT);
  363.     fflush(stdout);
  364.  
  365. #ifdef LOG
  366.     syslog(LOG_ERR, "%s transfer_timeout", hostname);
  367. #endif
  368.  
  369.     (void) unlink(tempfile);
  370.  
  371.     exit(1);
  372. }
  373.  
  374. #endif /* XFER_TIMEOUT */
  375.  
  376.